using System;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Xsl;
using Microsoft.XLANGs.BaseTypes;

namespace MapTestFramework.Common
{
    /// <summary>
    /// Represents a map executer that transforms XML instances using a BizTalk map represented by a TransformBase class.
    /// </summary>
    public class TransformBaseMapExecuter : IMapExecuter
    {
        #region Constructor And Initializing Members

        /// <summary>
        /// Initializes a new instance of the TransformBaseMapExecuter class with the specified map.
        /// </summary>
        /// <param name="map">TransformBase instance.</param>
        [CLSCompliant(false)]
        public TransformBaseMapExecuter(TransformBase map)
        {
            if (map == null)
                throw new ArgumentNullException("map");

            _xsltDocument = new XmlDocument();
            _xsltDocument.LoadXml(map.XmlContent);

            _xsltExtensionDocument = new XmlDocument();
            _xsltExtensionDocument.LoadXml(map.XsltArgumentListContent);
            return;
        }

        #endregion

        #region IMapExecuter Members

        public void ExecuteMap(string sourcePath, string targetPath)
        {
            ExceptionHelper.CheckEmptyOrNullValue(sourcePath, "sourcePath");
            ExceptionHelper.CheckEmptyOrNullValue(targetPath, "targetPath");

            XmlDocument source = new XmlDocument();
            source.Load(sourcePath);
            using (XmlWriter targetWriter = CreateXmlWriter(targetPath))
            {
                Transformer.Transform(source, Arguments, targetWriter, null);
                targetWriter.Flush();
            }
            return;
        }

        #endregion

        #region Helper Members

        private static XmlWriter CreateXmlWriter(string targetPath)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.ConformanceLevel = ConformanceLevel.Auto;
            settings.Indent = true;
            settings.IndentChars = new string(' ', 4);
            return XmlWriter.Create(targetPath, settings);
        }

        private XsltArgumentList _arguments;
        private XmlDocument _xsltDocument = null;
        private XmlDocument _xsltExtensionDocument = null;
        private XslTransform m_Transformer;

		private XsltArgumentList Arguments
		{
			get
			{
				if (_arguments == null)
				{
					XsltArgumentList arguments = new XsltArgumentList();
					XmlNodeList extensions = _xsltExtensionDocument.SelectNodes("//ExtensionObjects/ExtensionObject");
					foreach (XmlNode extension in extensions)
					{
						XmlExtensionNode extensionNode = new XmlExtensionNode(extension);
						extensionNode.AddArgument(arguments);
					}
					_arguments = arguments;
				}
				return _arguments;
			}
		}
        /// <summary>
        /// 
        /// </summary>
        /// <remarks>
        /// Old style transformation is used since it reflects the way BizTalk transforms messages.
        /// </remarks>
        private XslTransform Transformer
        {
            get
            {
                if (m_Transformer == null)
                {
                    XslTransform transformer = new XslTransform();
                    transformer.Load(_xsltDocument, (XmlResolver)null,
                        GetType().Assembly.Evidence);
                    m_Transformer = transformer;
                }
                return m_Transformer;
            }
        }

        #endregion
    }
}
